<?php

/**
 * This is the model class for a User in Yum
 *
 * The followings are the available columns in table '{{users}}':
 * @property integer $id
 * @property string $username
 * @property string $password
 * @property string $activationKey
 * @property integer $createtime
 * @property integer $lastvisit
 * @property integer $superuser
 * @property integer $status
 *
 * Relations
 * @property YumProfile $profile
 * @property array $roles array of YumRole
 * @property array $users array of YumUser
 *
 * Scopes:
 * @property YumUser $active
 * @property YumUser $notactive
 * @property YumUser $banned
 * @property YumUser $superuser
 *
 */
class YumUser extends YumActiveRecord
{
	const STATUS_INACTIVE = 0;
	const STATUS_ACTIVE = 1;
	const STATUS_BANNED = -1;
	const STATUS_REMOVED = -2;

	public $username;
	public $password;
	public $activationKey;
	public $email;
	public $cmnd;
	public $password_changed = false;
	public $lastvisit;

	public function behaviors()
	{
		return array(
				'CAdvancedArBehavior' => array(
					'class' => 'backend.modules.user.components.CAdvancedArBehavior'));
	}

	public static function model($className = __CLASS__)
	{
		return parent::model($className);
	}

	public function delete()
	{
		if (Yum::module()->trulyDelete)
			return parent::delete();
		else {
			$this->status = self::STATUS_REMOVED;
			return $this->save(false, array('status'));
		}
	}

	public function afterDelete()
	{
		if (Yum::hasModule('profiles') && $this->profile !== null)
			$this->profile->delete();

		Yum::log(Yum::t('User {username} (id: {id}) has been deleted', array(
						'{username}' => $this->username,
						'{id}' => $this->id)));
		return parent::afterDelete();
	}

	public function isOnline()
	{
		return $this->lastaction > time() - Yum::module()->offlineIndicationTime;
	}

	// If Online status is enabled, we need to set the timestamp of the
	// last action when a user does something
	public function setLastAction()
	{
		if (Yii::app()->user->isGuest) {
			$this->lastaction = time();
			return $this->save();
		}
	}

	public function getLogins()
	{
		$sql = "select count(*) from activities where user_id = {$this->id} and action = 'login'";
		$result = Yii::app()->db->createCommand($sql)->queryAll();
		return $result[0]['count(*)'];
	}

	public function logout()
	{
		if (Yum::module()->enableOnlineStatus && !Yii::app()->user->isGuest) {
			$this->lastaction = 0;
			$this->save('lastaction');
		}
	}

	public function isActive()
	{
		return $this->status == YumUser::STATUS_ACTIVE;
	}

	/*
	// This function tries to generate a as human-readable password as possible
	public static function generatePassword()
	{
		$consonants = array("b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "n", "p", "r", "s", "t", "v", "w", "x", "y", "z");
		$vocals = array("a", "e", "i", "o", "u");

		$password = '';

		srand((double)microtime() * 1000000);
		for ($i = 1; $i <= 4; $i++) {
			$password .= $consonants[rand(0, 19)];
			$password .= $vocals[rand(0, 4)];
		}
		$password .= rand(0, 9);

		return $password;
	}
	*/
	
	/**
	 * Generate a random password
	 *
	 * @static
	 * @param	int		$length	Length of the password to generate
	 * @return	string			Random Password
	 */
	public function generatePassword($length = 8) {
		$salt = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
		$len = strlen ( $salt );
		$makepass = '';
		
		$stat = @stat ( __FILE__ );
		if (empty ( $stat ) || ! is_array ( $stat ))
			$stat = array (php_uname () );
		
		mt_srand ( crc32 ( microtime () . implode ( '|', $stat ) ) );
		
		for($i = 0; $i < $length; $i ++) {
			$makepass .= $salt [mt_rand ( 0, $len - 1 )];
		}
		return $makepass;
	}

	// Which memberships are bought by the user
	public function getActiveMemberships()
	{
		if (!Yum::hasModule('membership'))
			return array();

		Yii::import('backend.modules.membership.models.*');

		$roles = array();
		if ($this->memberships)
			foreach ($this->memberships as $membership) {
				if ($membership->end_date > time())
					$roles[] = $membership->role;
			}

		return $roles;
	}

	public function search()
	{
		$criteria = new CDbCriteria;

		if (Yum::hasModule('profile') && isset($this->email)){
			$criteria->with = array('profile');
			if (isset($this->email))
				$criteria->addSearchCondition('profile.email', $this->email, true);
			if (isset($this->cmnd)){
				$criteria->addSearchCondition('profile.cmnd', $this->cmnd, true);
			}
		}
		
		// Show newest users first by default
		if (!isset($_GET['YumUser_sort']))
			$criteria->order = 't.createtime DESC';

		$criteria->together = false;
		$criteria->compare('t.id', $this->id, true);
		$criteria->compare('t.username', $this->username, true);
		$criteria->compare('t.status', $this->status);
		$criteria->compare('t.superuser', $this->superuser);
		$criteria->compare('t.createtime', $this->createtime, true);
		$criteria->compare('t.lastvisit', $this->lastvisit, true);

		return new CActiveDataProvider(get_class($this), array(
					'criteria' => $criteria,
					'pagination' => array('pageSize' => 10),
					));
	}

	public function beforeValidate()
	{
		if ($this->isNewRecord)
			$this->createtime = time();

		return true;
	}

	public function setPassword($password)
	{
		if ($password != '') {
			$this->password = YumUser::encryptPassword($password);
			$this->lastpasswordchange = time();
			$this->password_changed = true;
			if (!$this->isNewRecord)
				return $this->update();
			else
				return $this;
		}
	}

	public function afterSave()
	{
		if (Yum::hasModule('profile') && Yum::module('profile')->enablePrivacySetting) {
			// create a new privacy setting, if not already available
			$setting = YumPrivacySetting::model()->cache(0)->findByPk($this->id);
			if (!$setting) {
				$setting = new YumPrivacySetting();
				$setting->user_id = $this->id;
				$setting->save();
			}

			if ($this->isNewRecord) {
				Yum::log(Yum::t('A user has been created: user: {user}', array(
								'{user}' => json_encode($this->attributes))));


			}
		}
		return parent::afterSave();
	}

	/**
	 * Returns resolved table name (incl. table prefix when it is set in db configuration)
	 * Following algorith of searching valid table name is implemented:
	 *  - try to find out table name stored in currently used module
	 *  - if not found try to get table name from UserModule configuration
	 *  - if not found user default {{users}} table name
	 * @return string
	 */
	public function tableName()
	{
		if (isset(Yum::module()->usersTable))
			$this->_tableName = Yum::module()->usersTable;
		elseif (isset(Yii::app()->modules['user']['usersTable']))
			$this->_tableName = Yii::app()->modules['user']['usersTable'];
		else
			$this->_tableName = '{{users}}'; // fallback if nothing is set

		return Yum::resolveTableName($this->_tableName, $this->getDbConnection());
	}

	public function rules()
	{
		$passwordRequirements = Yum::module()->passwordRequirements;
		$usernameRequirements = Yum::module()->usernameRequirements;

		$passwordrule = array_merge(array('password', 'YumPasswordValidator'), $passwordRequirements);

		$rules[] = $passwordrule;

		$rules[] = array('username', 'length',
				'max' => $usernameRequirements['maxLen'],
				'min' => $usernameRequirements['minLen'],
				'message' => Yum::t(
					'Username length needs to be between {minLen} and {maxlen} characters', array(
						'{minLen}' => $usernameRequirements['minLen'],
						'{maxLen}' => $usernameRequirements['maxLen'])));

		$rules[] = array('username','unique','message' => Yii::t('account', "Tên tài khoản này đã tồn tại."));
		$rules[] = array(
				'username',
				'match',
				'pattern' => $usernameRequirements['match'],
				'message' => Yii::t('account', 'Incorrect symbol\'s. (A-z0-9)'));
		$rules[] = array('status', 'in', 'range' => array(0, 1, 2, 3, -1, -2));
		$rules[] = array('superuser', 'in', 'range' => array(0, 1));
		$rules[] = array('username, createtime, lastpasswordchange, superuser, status', 'required');
		$rules[] = array('notifyType, avatar', 'safe');
		$rules[] = array('password', 'required', 'on' => array('insert'));
		$rules[] = array('createtime, lastvisit, lastaction, superuser, status', 'numerical', 'integerOnly' => true);

		if (Yum::hasModule('avatar')) {
			// require an avatar image in the avatar upload screen
			$rules[] = array('avatar', 'required', 'on' => 'avatarUpload');

			// if automatic scaling is deactivated, require the exact size	
			$rules[] = array('avatar', 'EPhotoValidator',
					'allowEmpty' => true,
					'mimeType' => array('image/jpeg', 'image/png', 'image/gif'),
					'maxWidth' => Yum::module('avatar')->avatarMaxWidth,
					'maxHeight' => Yum::module('avatar')->avatarMaxWidth,
					'minWidth' => 50,
					'minHeight' => 50,
					'on' => 'avatarSizeCheck');
		}
		return $rules;
	}

	public function hasRole($role_title)
	{
		if (!Yum::hasModule('role'))
			return false;
		
		foreach ($this->roles as $role)
			if ($role->id == $role_title || $role->name == $role_title)
				return true;	
		/*
		foreach ($this->roles as $role)
			if ($role->id == $role_title || $role->title == $role_title)
				return true;
		*/		

		return false;
	}

	public function getRoles()
	{
		if (Yum::hasModule('role')) {
			Yii::import("backend.modules.srbac.components.Helper");
			Yii::import("backend.modules.srbac.models.*");
			$this->roles = Helper::getUserAssignedRoles($this->id);
			$roles = '';
			foreach ($this->roles as $role){
				$roles .= ' ' . $role->name;
			}	

			return $roles;
			/*
			Yii::import('backend.modules.role.models.*');
			$roles = '';
			foreach ($this->roles as $role)
				$roles .= ' ' . $role->title;

			return $roles;
			*/
		}
	}

	public function getPermissions()
	{
		if (!Yum::hasModule('role'))
			return array();
		
		Yii::import('backend.modules.role.models.*');
		$permissions = array();
		
		$roles = $this->roles;
		if (Yum::hasModule('membership'))
			$roles = array_merge($roles, $this->getActiveMemberships());
			
		//Using srbac to check permission
		/*
		foreach ($roles as $role) {
			$sql = "select id, action.title from permission left join action on action.id = permission.action where type = 'role' and principal_id = {$role->id}";
			foreach (Yii::app()->db->cache(500)->createCommand($sql)->query()->readAll() as $permission)
				$permissions[$permission['id']] = $permission['title'];
		}
		*/
		return $permissions;
	}

	public function can($action)
	{
		foreach ($this->getPermissions() as $permission)
			if ($permission == $action)
				return true;

		return false;
	}

	public function relations()
	{
		if (Yum::hasModule('profile'))
			Yii::import('backend.modules.profile.models.*');
		return array(
				'permissions' => array(self::HAS_MANY, 'YumPermission', 'principal_id'),
				'managed_by' => array(self::HAS_MANY, 'YumPermission', 'subordinate_id'),
				'messages' => array(self::HAS_MANY, 'YumMessage', 'to_user_id', 'order' => 'messages.id DESC'),
				'sent_messages' => array(self::HAS_MANY, 'YumMessage', 'from_user_id'),
				'visits' => array(self::HAS_MANY, 'YumProfileVisit', 'visited_id'),
				'visited' => array(self::HAS_MANY, 'YumProfileVisit', 'visitor_id'),
				'profile' => array(self::HAS_ONE, 'YumProfile', 'user_id'),
				'friendships' => array(self::HAS_MANY, 'YumFriendship', 'inviter_id'),
				'friendships2' => array(self::HAS_MANY, 'YumFriendship', 'friend_id'),
				'friendship_requests' => array(self::HAS_MANY, 'YumFriendship', 'friend_id', 'condition' => 'status = 1'), // 1 = FRIENDSHIP_REQUEST
				//'roles' => array(self::MANY_MANY, 'YumRole', Yum::module('role')->userHasRoleTable . '(userid, itemname)'),
				//'memberships' => array(self::HAS_MANY, 'YumMembership', 'user_id'),
				'privacy' => array(self::HAS_ONE, 'YumPrivacySetting', 'user_id'),
				//'user_phonenumbers' => array(self::HAS_MANY, 'UserPhoneNumbers', 'userid'),
				);
	}

	public function isFriendOf($invited_id)
	{
		foreach ($this->getFriendships() as $friendship) {
			if ($friendship->inviter_id == $this->id && $friendship->friend_id == $invited_id)
				return $friendship->status;
		}

		return false;
	}

	public function getFriendships()
	{
		$condition = 'inviter_id = :uid or friend_id = :uid';
		return YumFriendship::model()->cache(500)->findAll($condition, array(':uid' => $this->id));
	}

	// Friends can not be retrieve via the relations() method because a friend
	// can either be in the invited_id or in the friend_id column.
	// set $everything to true to also return pending and rejected friendships
	public function getFriends($everything = false)
	{
		if ($everything)
			$condition = 'inviter_id = :uid';
		else
			$condition = 'inviter_id = :uid and status = 2';

		$friends = array();
		Yii::import('backend.modules.friendship.models.YumFriendship');
		$friendships = YumFriendship::model()->findAll($condition, array(
					':uid' => $this->id));
		if ($friendships != NULL && !is_array($friendships))
			$friendships = array($friendships);

		if ($friendships)
			foreach ($friendships as $friendship)
				$friends[] = YumUser::model()->findByPk($friendship->friend_id);

		if ($everything)
			$condition = 'friend_id = :uid';
		else
			$condition = 'friend_id = :uid and status = 2';

		$friendships = YumFriendship::model()->findAll($condition, array(
					':uid' => $this->id));

		if ($friendships != NULL && !is_array($friendships))
			$friendships = array($friendships);


		if ($friendships)
			foreach ($friendships as $friendship)
				$friends[] = YumUser::model()->findByPk($friendship->inviter_id);

		return $friends;
	}

	// Registers a user 
	public function register($username = null, $password = null, $email = null)
	{
		if ($username !== null && $password !== null) {
			// Password equality is checked in Registration Form
			$this->username = $username;
			$this->password = $this->encryptPassword($password);
		}
		$this->activationKey = $this->generateActivationKey(true);
		$this->createtime = time();
		$this->superuser = 0;

		// Users stay banned until they confirm their email address.
		$this->status = YumUser::STATUS_ACTIVE;

		if ($this->save()) {
		   if(isset($this->id) && $this->id > 0){
		   		$profile = new YumProfile();
				$profile->email = $email;
				$profile->fullname = $username;
		    	$profile->user_id = $this->id;
		    	if($profile->save()){		 
		    		YumActivityController::logActivity ( $this, YumActivityLog::LOG_PROFILE_INSERT, 'User {username} insert profile', json_encode ( array (
							'{username}' => $this->username ) ), 0, YumActivityLog::ID );   	
		    		$this->profile = $profile;
		    		if($profile->user_id == 0){
		    			YumActivityController::logActivity ( $this, YumActivityLog::LOG_PROFILE_INSERT_ERROR, 'User {username} registered with email: {email}', json_encode ( array (
							'{username}' => $this->username ) ), 0, YumActivityLog::ID);
		    		}
		    	}	    	
		   }
		   Yum::log(Yum::t('User {username} registered. Generated activation Url is {activation_url} and has been sent to {email}',
						array(
							'{username}' => $this->username,
							'{email}' => $this->profile->email,
							'{activation_url}' => $this->getActivationUrl()))
					);

			return $this;
		}

		return false;
	}

	public function getActivationUrl()
	{
		/**
		 * Quick check for a enabled Registration Module
		 */
		if (Yum::module('registration')) {
			$activationUrl = Yum::module('registration')->activationUrl;
			if (is_array($activationUrl) && isset($this->profile)) {
				$activationUrl = $activationUrl[0];
				$params['key'] = $this->activationKey;
				$params['email'] = $this->profile->email;

				return Yii::app()->controller->createAbsoluteUrl($activationUrl, $params);
			}
		}
		return Yum::t('Activation Url cannot be retrieved');
	}

	public function isPasswordExpired()
	{
		$distance = Yum::module('user')->password_expiration_time * 60 * 60;
		return $this->lastpasswordchange - $distance > time();
	}

	/**
	 * Activation of an user account.
	 * If everything is set properly, and the emails exists in the database,
	 * and is associated with a correct user, and this user has the status
	 * NOTACTIVE and the given activationKey is identical to the one in the
	 * database then generate a new Activation key to avoid double activation,
	 * set the status to ACTIVATED and save the data
	 * Error Codes:
	 * -1 : User is not inactive, it can not be activated
	 * -2 : Wrong activation key
	 * -3 : Profile found, but no user - database inconsistency?
	 */
	public static function activate($email, $key)
	{
		Yii::import('backend.modules.profile.models.*');

		if ($profile = YumProfile::model()->find("email = :email", array(
						':email' => $email))
			 ) {
			if ($user = $profile->user) {
				if ($user->status != self::STATUS_INACTIVE)
					return -1;
				if ($user->activationKey == $key) {
					$user->activationKey = $user->generateActivationKey(true);
					$user->status = self::STATUS_ACTIVE;
					if ($user->save(false, array('activationKey', 'status'))) {
						Yum::log(Yum::t('User {username} has been activated', array(
										'{username}' => $user->username)));
						if (Yum::hasModule('messages')
								&& Yum::module('registration')->enableActivationConfirmation
							 ) {
							Yii::import('backend.modules.messages.models.YumMessage');
//							YumMessage::write($user, 1,
//									Yum::t('Your activation succeeded'),
//									YumTextSettings::getText('text_email_activation', array(
//											'{username}' => $user->username,
//											'{link_login}' =>
//											Yii::app()->controller->createUrl('//user/user/login'))));
						}

						return $user;
					}
				} else return -2;
			} else return -3;
		}
		return false;
	}

	/**
	 * @params boolean $activate Whether to generate activation key when user is registering first time (false)
	 * or when it is activating (true)
	 * @params string $password password entered by user
	 * @param array $params, optional, to allow passing values outside class in inherited classes
	 * By default it uses password and microtime combination to generated activation key
	 * When user is activating, activation key becomes micortime()
	 * @return string
	 */
	public function generateActivationKey($activate = false)
	{
		$this->activationKey = $activate
			? YumUser::encrypt(microtime())
			: YumUser::encrypt(microtime() . $this->password);

//		$this->save(false, array('activationKey'));
		return $this->activationKey;
	}

	public function attributeLabels()
	{
		return array(
				'id' => Yum::t('#'),
				'username' => Yum::t("Username"),
				'password' => Yum::t("Password"),
				'verifyPassword' => Yum::t("Retype password"),
				'verifyCode' => Yum::t("Verification code"),
				'activationKey' => Yum::t("Activation key"),
				'createtime' => Yum::t("Registration date"),
				'lastvisit' => Yum::t("Last visit"),
				'lastaction' => Yum::t("Online status"),
				'superuser' => Yum::t("Superuser"),
				'status' => Yum::t("Status"),
				'avatar' => Yum::t("Avatar image"),
				);
	}

	/**
	 * This function is used for password encryption.
	 * @return hash string.
	 */
	public static function encrypt($string = "")
	{
		$salt = Yum::module()->salt;
		$hashFunc = Yum::module()->hashFunc;
		$string = sprintf("%s%s%s", $salt, $string, $salt);
		
		if (!function_exists($hashFunc))
			throw new CException('Function `' . $hashFunc . '` is not a valid callback for hashing algorithm.');

		return $hashFunc($string);
	}

	public function encryptPassword($string) {
		$salt = self::generatePassword ( 32 );
		$crypt = self::getCryptedPassword ( $string, $salt );
		$password = $crypt . ':' . $salt;
		return $password;
	}
	
	public function limit($limit = 10)
	{
		$this->getDbCriteria()->mergeWith(array(
					'limit' => $limit,
					));
		return $this;
	}

	public function scopes()
	{
		return array(
				'active' => array('condition' => 'status=' . self::STATUS_ACTIVE,),
				'inactive' => array('condition' => 'status=' . self::STATUS_INACTIVE,),
				'banned' => array('condition' => 'status=' . self::STATUS_BANNED,),
				'superuser' => array('condition' => 'superuser = 1',),
				'public' => array(
					'join' => 'LEFT JOIN privacysetting on t.id = privacysetting.user_id',
					'condition' => 'appear_in_search = 1',),
				);
	}

	public static function itemAlias($type, $code = NULL)
	{
		$_items = array(
				'UserStatus' => array(
					'0' => Yum::t('Not active'),
					'1' => Yum::t('Active'),
					'-1' => Yum::t('Banned'),
					'-2' => Yum::t('Deleted'),
					),
				'AdminStatus' => array(
					'0' => Yum::t('No'),
					'1' => Yum::t('Yes'),
					),
				);
		if (isset($code))
			return isset($_items[$type][$code]) ? $_items[$type][$code] : false;
		else
			return isset($_items[$type]) ? $_items[$type] : false;
	}

	/**
	 * Get all users with a specified role.
	 * @param string $roleTitle title of role to be searched
	 * @return array users with specified role. Null if none are found.
	 */
	public static function getUsersByRole($roleTitle)
	{
		$role = YumRole::model()->findByAttributes(array('title' => $roleTitle));
		return $role ? $role->users : null;
	}

	/**
	 * Return admins.
	 * @return array syperusers names
	 */
	public static function getAdmins()
	{
		$admins = YumUser::model()->active()->superuser()->findAll();
		$returnarray = array();
		foreach ($admins as $admin)
			array_push($returnarray, $admin->username);
		return $returnarray;
	}

	public function getAvatar($thumb = false)
	{
		if (Yum::hasModule('avatar') && $this->profile) {
			$return = '<div class="avatar">';

			$options = array();
			if ($thumb)
				$options = array('style' => 'width: 50px; height:50px;');
			else
				$options = array('style' => 'width: ' . Yum::module('avatar')->avatarDisplayWidth . 'px;');

			if (isset($this->avatar) && $this->avatar)
				$return .= CHtml::image(Yii::app()->baseUrl . '/'
						. $this->avatar, 'Avatar', $options);
			else
				$return .= CHtml::image(Yii::app()->getAssetManager()->publish(
							Yii::getPathOfAlias('YumAssets.images') . ($thumb
								? '/no_avatar_available_thumb.jpg' : '/no_avatar_available.jpg'),
							Yum::t('No image available'), array(
								'title' => Yum::t('No image available'))));
			$return .= '</div><!-- avatar -->';
			return $return;
		}
	}
	
	/**
	 * Formats a password using the current encryption.
	 *
	 * @access	public
	 * @param	string	$plaintext	The plaintext password to encrypt.
	 * @param	string	$salt		The salt to use to encrypt the password. []
	 * If not present, a new salt will be
	 * generated.
	 * @param	string	$encryption	The kind of pasword encryption to use.
	 * Defaults to md5-hex.
	 * @param	boolean	$show_encrypt  Some password systems prepend the kind of
	 * encryption to the crypted password ({SHA},
	 * etc). Defaults to false.
	 *
	 * @return string  The encrypted password.
	 */
	public function getCryptedPassword($plaintext, $salt = '', $encryption = 'md5-hex', $show_encrypt = false) {
		// Get the salt to use.
		$salt = self::getSalt ( $encryption, $salt, $plaintext );
		
		// Encrypt the password.
		switch ($encryption) {
			case 'plain' :
				return $plaintext;
			
			case 'sha' :
				$encrypted = base64_encode ( mhash ( MHASH_SHA1, $plaintext ) );
				return ($show_encrypt) ? '{SHA}' . $encrypted : $encrypted;
			
			case 'crypt' :
			case 'crypt-des' :
			case 'crypt-md5' :
			case 'crypt-blowfish' :
				return ($show_encrypt ? '{crypt}' : '') . crypt ( $plaintext, $salt );
			
			case 'md5-base64' :
				$encrypted = base64_encode ( mhash ( MHASH_MD5, $plaintext ) );
				return ($show_encrypt) ? '{MD5}' . $encrypted : $encrypted;
			
			case 'ssha' :
				$encrypted = base64_encode ( mhash ( MHASH_SHA1, $plaintext . $salt ) . $salt );
				return ($show_encrypt) ? '{SSHA}' . $encrypted : $encrypted;
			
			case 'smd5' :
				$encrypted = base64_encode ( mhash ( MHASH_MD5, $plaintext . $salt ) . $salt );
				return ($show_encrypt) ? '{SMD5}' . $encrypted : $encrypted;
			
			case 'aprmd5' :
				$length = strlen ( $plaintext );
				$context = $plaintext . '$apr1$' . $salt;
				$binary = $this->_bin ( md5 ( $plaintext . $salt . $plaintext ) );
				
				for($i = $length; $i > 0; $i -= 16) {
					$context .= substr ( $binary, 0, ($i > 16 ? 16 : $i) );
				}
				for($i = $length; $i > 0; $i >>= 1) {
					$context .= ($i & 1) ? chr ( 0 ) : $plaintext [0];
				}
				
				$binary = $this->_bin ( md5 ( $context ) );
				
				for($i = 0; $i < 1000; $i ++) {
					$new = ($i & 1) ? $plaintext : substr ( $binary, 0, 16 );
					if ($i % 3) {
						$new .= $salt;
					}
					if ($i % 7) {
						$new .= $plaintext;
					}
					$new .= ($i & 1) ? substr ( $binary, 0, 16 ) : $plaintext;
					$binary = $this->_bin ( md5 ( $new ) );
				}
				
				$p = array ();
				for($i = 0; $i < 5; $i ++) {
					$k = $i + 6;
					$j = $i + 12;
					if ($j == 16) {
						$j = 5;
					}
					$p [] = $this->_toAPRMD5 ( (ord ( $binary [$i] ) << 16) | (ord ( $binary [$k] ) << 8) | (ord ( $binary [$j] )), 5 );
				}
				
				return '$apr1$' . $salt . '$' . implode ( '', $p ) . $this->_toAPRMD5 ( ord ( $binary [11] ), 3 );
			
			case 'md5-hex' :
			default :
				$encrypted = ($salt) ? md5 ( $plaintext . $salt ) : md5 ( $plaintext );
				return ($show_encrypt) ? '{MD5}' . $encrypted : $encrypted;
		}
	}
	
	/**
	 * Returns a salt for the appropriate kind of password encryption.
	 * Optionally takes a seed and a plaintext password, to extract the seed
	 * of an existing password, or for encryption types that use the plaintext
	 * in the generation of the salt.
	 *
	 * @access public
	 * @param string $encryption  The kind of pasword encryption to use.
	 * Defaults to md5-hex.
	 * @param string $seed		The seed to get the salt from (probably a
	 * previously generated password). Defaults to
	 * generating a new seed.
	 * @param string $plaintext   The plaintext password that we're generating
	 * a salt for. Defaults to none.
	 *
	 * @return string  The generated or extracted salt.
	 */
	public function getSalt($encryption = 'md5-hex', $seed = '', $plaintext = '') {
		// Encrypt the password.
		switch ($encryption) {
			case 'crypt' :
			case 'crypt-des' :
				if ($seed) {
					return substr ( preg_replace ( '|^{crypt}|i', '', $seed ), 0, 2 );
				} else {
					return substr ( md5 ( mt_rand () ), 0, 2 );
				}
				break;
			
			case 'crypt-md5' :
				if ($seed) {
					return substr ( preg_replace ( '|^{crypt}|i', '', $seed ), 0, 12 );
				} else {
					return '$1$' . substr ( md5 ( mt_rand () ), 0, 8 ) . '$';
				}
				break;
			
			case 'crypt-blowfish' :
				if ($seed) {
					return substr ( preg_replace ( '|^{crypt}|i', '', $seed ), 0, 16 );
				} else {
					return '$2$' . substr ( md5 ( mt_rand () ), 0, 12 ) . '$';
				}
				break;
			
			case 'ssha' :
				if ($seed) {
					return substr ( preg_replace ( '|^{SSHA}|', '', $seed ), - 20 );
				} else {
					return mhash_keygen_s2k ( MHASH_SHA1, $plaintext, substr ( pack ( 'h*', md5 ( mt_rand () ) ), 0, 8 ), 4 );
				}
				break;
			
			case 'smd5' :
				if ($seed) {
					return substr ( preg_replace ( '|^{SMD5}|', '', $seed ), - 16 );
				} else {
					return mhash_keygen_s2k ( MHASH_MD5, $plaintext, substr ( pack ( 'h*', md5 ( mt_rand () ) ), 0, 8 ), 4 );
				}
				break;
			
			case 'aprmd5' :
				/* 64 characters that are valid for APRMD5 passwords. */
				$APRMD5 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
				
				if ($seed) {
					return substr ( preg_replace ( '/^\$apr1\$(.{8}).*/', '\\1', $seed ), 0, 8 );
				} else {
					$salt = '';
					for($i = 0; $i < 8; $i ++) {
						$salt .= $APRMD5 {rand ( 0, 63 )};
					}
					return $salt;
				}
				break;
			
			default :
				$salt = '';
				if ($seed) {
					$salt = $seed;
				}
				return $salt;
				break;
		}
	}
	
	public function verifyPassword($password){
		$parts = explode ( ':', $this->password );
		$crypt = $parts [0];
		$salt = @$parts [1]; // Ignore if out of range
		$testcrypt = $this->getCryptedPassword ( $password, $salt );
		if ($crypt == $testcrypt) {
			return true;
		}
		return false;
	}
	
	public function getEmail() {
		if(isset($this->profile) && isset($this->profile->email)){
			return $this->profile->email;
		}
		return "";
	}
	
	public function getCMND() {
		if(isset($this->profile) && isset($this->profile->cmnd)){
			return $this->profile->cmnd;
		}
		return "";
	}
	
	public function loadByEmail($email) {
		
	}
	
}
